<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<meta name="viewport" content="width=device-width, initial-scale=1">
		<meta http-equiv="X-UA-Compatible" content="ie=edge,chrome=1">
		<meta name="referrer" content="never">
		<title></title>
		<style type="text/css">
			*{
				margin: 0;
				padding: 0;
			}
			body{
				background-color: #222;
			}
			#myCanvas{
				position: absolute;
				left: 0;
				top: 0;
			}
			canvas{
				pointer-events: none;
			}
		</style>
	</head>
	<body>
		<canvas id="myCanvas" width="600" height="600"></canvas>
		<script type="text/javascript">
			!function (w,e) {
				function Demo(option){
					Object.assign(this,{
						el: "#myCanvas",
						mainWidth: w.innerWidth,
						mainHeight: w.innerHeight,
						canvasContextList: [],
						canvasList: [],
						drawList: [],
						waterBall: {
							name: "water ball"
						}
					},option)
					this.init()
				}
				Demo.prototype = {
					init(){
						this.canvas = e.querySelector(this.el)
						this.canvas.style.zIndex = 2
						this.canvas.setAttribute("width",this.mainWidth)
						this.canvas.setAttribute("height",this.mainHeight)
						this.cx = this.canvas.getContext("2d")
						this.canvasContextList.push(this.cx)
						this.canvasList.push(this.canvas)
						this.addEvents()
						this.start(this.waterBall)
					},
					addEvents(){
						w.addEventListener("resize",evt => {
							this.mainWidth = w.innerWidth
							this.mainHeight = w.innerHeight
							this.canvasList.forEach(c => {
								c.setAttribute("width", w.innerWidth)
								c.setAttribute("height", w.innerHeight)
							})
						})
					},
					draw(frame,once){
						this.timer && clearInterval(this.timer)
						this.drawList.push({frame,once})
						if(this.drawList.every(obj => obj.once)){
							this.drawList.forEach(obj => obj.frame())
						}else{
							this.timer = setInterval(() => {
								this.ms = performance.now()
								this.canvasContextList.forEach(cx => {
									cx.clearRect(0,0,this.mainWidth,this.mainHeight)
								})
								this.drawList.forEach(obj => obj.frame())
								this.canvasContextList.forEach(cx => {
								})
							},1000/60)
						}
					},
					start(option){
						let cx = this.cx
						let se = [1,0]
						{
							;
							// 第一次失败的尝试
							// this.draw(() => {
							// 	cx.font= "40px Arial"
							// 	let _step = (se[0] - se[1]) / 100
							// 	se[1] += _step
							// 	option.forEach(op => {
							// 		cx.save()
							// 		let o = [this.mainWidth * op.origin[0] / 100, this.mainHeight * op.origin[1] / 100]
							// 		let r = op.radius
							// 		let step = op.radius * 2 / 3
							// 		let start = [o[0] - r - step * 2,o[1] + r]
							// 		let t = this.ms
							// 		let rnd = op.roundNess
							// 		let h = op.waveHeight * op.radius
							// 		let text = Math.round(op.value * se[1]) + "%"
									
							// 		// ****************************** 绘制球部分
							// 		cx.fillStyle = op.bgColor
							// 		cx.beginPath()
							// 		cx.arc(...o, op.radius, 0, Math.PI * 2)
							// 		cx.fill()
							// 		cx.clip()
									
							// 		// ****************************** 绘制波浪部分
							// 		let drawWave = index => {
							// 			let offset = [(this.ms / 20 / (index + 1) % (step * 2)), op.value * r / 50 * se[1]]
							// 			cx.beginPath()
							// 			cx.moveTo(start[0] + offset[0],o[1] + r - h - offset[1])
							// 			for(let i = 0; i < 5; i++){
							// 				if(i % 2 === 0){
							// 					cx.bezierCurveTo(
							// 					step * (i + rnd) + start[0] + offset[0],o[1] + r - h - offset[1],
							// 					step * (i + 1 - rnd) + start[0] + offset[0],o[1] + r - offset[1],
							// 					step * (i + 1) + start[0] + offset[0],o[1] + r - offset[1])
							// 				}else{
							// 					cx.bezierCurveTo(
							// 					step * (i + rnd) + start[0] + offset[0],o[1] + r - offset[1],
							// 					step * (i + 1 - rnd) + start[0] + offset[0],o[1] + r - h - offset[1],
							// 					step * (i + 1) + start[0] + offset[0],o[1] + r - h - offset[1])
							// 				}
							// 			}
							// 			cx.lineTo(o[0] + r + offset[0],o[1] + r)
							// 			cx.lineTo(start[0] + offset[0], start[1])
							// 			cx.closePath()
							// 			// cx.globalCompositeOperation = "source-atop"
							// 			cx.shadowBlur = 10
							// 			cx.shadowColor = "#000000"
							// 			let gr = cx.createLinearGradient(0, o[1] + r, 0, o[1] - r)
							// 			op.colorStop.forEach(ctp => {
							// 				gr.addColorStop(...ctp)
							// 			})
							// 			cx.fillStyle = gr
							// 			cx.globalAlpha = .6 - index * .2
							// 			cx.fill()
							// 			cx.beginPath()
							// 		}
							// 		// drawWave(2)
							// 		drawWave(1)
							// 		drawWave(0)
									
							// 		// ****************************** 绘制文本部分
							// 		cx.globalCompositeOperation = "source-over"
							// 		cx.globalAlpha = 1
							// 		cx.fillStyle = "#fff"
							// 		cx.shadowColor = "#00000066"
							// 		cx.fillText(text,o[0] - cx.measureText(text).width / 2,o[1] + 16)
							// 		cx.restore()
							// 	})
							// })
						}
						
						option.forEach(op => {
							let o = [this.mainWidth * op.origin[0] / 100, this.mainHeight * op.origin[1] / 100]
							let r = op.radius
							let step = op.radius * 2 / 3
							let h = op.waveHeight * op.radius
							let start = [o[0] - r - step * 2,o[1] + r - h]
							let rnd = op.roundNess
							let path = []
							// 建模
							for(let i = 0; i < 5; i++){
								if(i % 2 === 0){
									path.push([
										step * (i + rnd) + start[0],o[1] + r - h,
										step * (i + 1 - rnd) + start[0],o[1] + r,
										step * (i + 1) + start[0],o[1] + r
									])
								}else{
									path.push([
										step * (i + rnd) + start[0],o[1] + r,
										step * (i + 1 - rnd) + start[0],o[1] + r - h,
										step * (i + 1) + start[0],o[1] + r - h
									])
								}
							}
							path.push([o[0] + r,o[1] + r])
							path.push([start[0],o[1] + r])
							let gr = cx.createLinearGradient(0, o[1] + r, 0, o[1] - r)
							op.colorStop.forEach(ctp => {
								gr.addColorStop(...ctp)
							})
							this.draw(() => {
								cx.save()
								let _step = (se[0] - se[1]) / 100
								se[1] += _step
								let t = this.ms
								let text = Math.round(op.value * se[1]) + "%"
								cx.font= "40px Arial"
								
								// ****************************** 绘制球部分
								cx.fillStyle = op.bgColor
								cx.beginPath()
								cx.arc(...o, op.radius, 0, Math.PI * 2)
								cx.fill()
								cx.clip()
								
								// ****************************** 绘制波浪部分
								
								let drawWave = index => {
									let offset = [(this.ms / 20 / (index + 1) % (step * 2)), op.value * r / 50 * se[1]]
									cx.beginPath()
									cx.moveTo(start[0] + offset[0],start[1] - offset[1])
									for(let i = 0; i < 5; i++){
										cx.bezierCurveTo(
										path[i][0] + offset[0],path[i][1] - offset[1],
										path[i][2] + offset[0],path[i][3] - offset[1],
										path[i][4] + offset[0],path[i][5] - offset[1])
									}
									cx.lineTo(path[5][0] + offset[0],path[5][1])
									cx.lineTo(path[6][0] + offset[0],path[6][1])
									cx.closePath()
									// cx.globalCompositeOperation = "source-atop"
									cx.shadowBlur = 10
									cx.shadowColor = "#000000"
									cx.fillStyle = gr
									cx.globalAlpha = .6 - index * .2
									cx.fill()
									cx.beginPath()
								}
								drawWave(2)
								drawWave(1)
								drawWave(0)
								
								// ****************************** 绘制文本部分
								// cx.globalCompositeOperation = "source-over"
								cx.globalAlpha = 1
								cx.fillStyle = "#fff"
								cx.shadowColor = "#00000066"
								cx.fillText(text,o[0] - cx.measureText(text).width / 2,o[1] + 16)
								cx.restore()
							})
						})
					}
				}
				w.Demo = Demo
			}(window,document)
			var d = new Demo({
				waterBall: [{
					radius: 100, // 半径 px
					origin: [50,50], // [width %, height %]
					value: 20, // height %
					waves: 2, // count
					bgColor: "#121a23",
					colorStop: [[0,"#7ae0ef"],[1,"#5e9fff"]],
					waveHeight: .2, // 波浪高度 px
					roundNess: .4, // 波峰/谷圆度
				},
				{
					radius: 100, // 半径 px
					origin: [80,50], // [width %, height %]
					value: 50, // height %
					waves: 2, // count
					bgColor: "#121a23",
					colorStop: [[0,"#7ae0ef"],[1,"#5e9fff"]],
					waveHeight: .2, // 波浪高度 (相对半径的倍率)
					roundNess: .4, // 波峰/谷圆度
				}]
			})
		</script>
	</body>
</html>